package projbd;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
// import java.sql.BatchUpdateException;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;


public class XMLParser extends DefaultHandler {
    
    private List<String> fathers = new ArrayList<String>();
    private List<Integer> siblingsPerFather = new ArrayList<Integer>();
    
    private XMLReader xr;
    private ArrayList<FileReader> files = new ArrayList<FileReader>();

    private String currentDeweyId = "1";
    private int currentPathId = 1;
    private int currentFileId = 1;
    private String currentText = new String();
    private Integer currentLevel = 1;
    private Integer currentSiblingNumber = 1;
    private Statement statement;

    private static final String sw = "'";
    
    public Statement getStatement() {
        return statement;
    }

    public void setStatement(Statement statement) {
        this.statement = statement;
    }

    public XMLParser() {
        super();
    }

    @Override
    public void startDocument() throws SAXException {
        System.out.println("start document");
    }

    @Override
    public void endDocument() throws SAXException {
        System.out.println("end document");

        try {
            statement.executeBatch();
        } catch (SQLException ex) {
            Logger.getLogger(XMLParser.class.getName()).log(Level.SEVERE, null, ex);
            System.out.println(ex.getNextException());

        }
    }
    
    @Override
    public void characters(char ch[], int start, int length) {
        
        // System.out.println(ch);
        String sqlStatement = new String();
        
        String text = new String(ch, start, length);
        currentText = text;
        currentText = currentText.trim();
        
        // System.out.println(currentText);
        currentText = currentText.replaceAll("'", "''");
        // System.out.println(currentText);
        
        if ((!currentText.isEmpty()) && (!currentText.equals("\n"))) {

            if (!(fathers.contains(currentDeweyId))) {
                fathers.add(currentDeweyId);
                siblingsPerFather.add(1);
            } else {
                int i = fathers.indexOf(currentDeweyId);
                int siblingNumber = siblingsPerFather.get(i);
                siblingNumber++;
                siblingsPerFather.set(i, siblingNumber);
            }

            int i = fathers.indexOf(currentDeweyId);
            currentSiblingNumber = siblingsPerFather.get(i);

            String oldDeweyId = currentDeweyId;
            
            if ((currentLevel != 1) && (currentLevel != 2)) {
                currentDeweyId = currentDeweyId + "." + currentSiblingNumber.toString();
            } 

            if (currentLevel == 2) {
                currentSiblingNumber--;
                currentDeweyId = currentDeweyId + "." + currentSiblingNumber.toString();
            }            
            
            String sqlStatementFiles = "INSERT INTO files(id,name) VALUES(" + currentFileId + "," + sw + currentSiblingNumber + sw + ")";
            String sqlStatementPaths = "INSERT INTO paths(id,path,file) VALUES(" + currentPathId + "," + sw + oldDeweyId + sw + "," + currentFileId + ")";            
            
            sqlStatement = "INSERT INTO dewey_edges(dewey,path_id,value,attributes,datatype,father_id) VALUES(" + sw + currentDeweyId + sw + ","
                                                             + currentPathId + "," 
                                                             + sw + currentText + sw + ","
                                                             + "NULL, 'text')";
    
            // System.out.println("Characters: " + currentText);
            // System.out.println(currentDeweyId);
            
//            try {
//                statement.execute(sqlStatementFiles);
//            } catch (SQLException ex) {
//                Logger.getLogger(XMLParser.class.getName()).log(Level.SEVERE, null, ex);
//                System.out.println(sqlStatementFiles);
//            }
//
//            try {
//                statement.execute(sqlStatementPaths);
//            } catch (SQLException ex) {
//                Logger.getLogger(XMLParser.class.getName()).log(Level.SEVERE, null, ex);
//                System.out.println(sqlStatementPaths);
//            }
//            
//            try {
//                statement.execute(sqlStatement);
//            } catch (SQLException ex) {
//                Logger.getLogger(XMLParser.class.getName()).log(Level.SEVERE, null, ex);
//                System.out.println(sqlStatement);
//            }
            
            try {
                statement.addBatch(sqlStatementFiles);
                statement.addBatch(sqlStatementPaths);
                statement.addBatch(sqlStatement);
            } catch (SQLException ex) {
                Logger.getLogger(ShakespeareXMLParser.class.getName()).log(Level.SEVERE, null, ex);
            }            
           
            currentFileId++;
            currentPathId++;            
            
            int j;
            for (j = (currentDeweyId.length()) - 1; (currentDeweyId.charAt(j) != '.') && (j > 0); j--) {
                continue;
            }
            currentDeweyId = currentDeweyId.substring(0, j);
            currentText = "";

        }        
        
    }
    
    @Override
    public void startElement(String uri, String name, String qName, Attributes atts) {
        
        String sqlStatement = new String();
        // String sqlStatementFiles = new String();
        // String sqlStatementPaths = new String();
        String value = "";
        String sqlStatementFiles;
        String sqlStatementPaths;
        
	if ("".equals (uri)) {
	    // System.out.println("Start element: " + qName);        
            value = qName;
        } else {
	    // System.out.println("Start element: {" + uri + "}" + name);
            value = uri + name;
        }
        
        // go one level deeper -> child node's dewey code is fatherscode.i
        // (i the order of the child amongst siblings)
        
        if (!(fathers.contains(currentDeweyId))) {
            fathers.add(currentDeweyId);
            siblingsPerFather.add(1);
        } else {
            int i = fathers.indexOf(currentDeweyId);
            int siblingNumber = siblingsPerFather.get(i);
            siblingNumber++;
            siblingsPerFather.set(i, siblingNumber);
        }

        int i = fathers.indexOf(currentDeweyId);
        currentSiblingNumber = siblingsPerFather.get(i);

        String oldDeweyId = currentDeweyId;
       
        if ((currentLevel != 1) && (currentLevel != 2)) {
            currentDeweyId = currentDeweyId + "." + currentSiblingNumber.toString();
        } 
        
        if (currentLevel == 2) {
            currentSiblingNumber--;
            currentDeweyId = currentDeweyId + "." + currentSiblingNumber.toString();
        }
        
        String attributes = new String();
        if (atts != null) {
            int length = atts.getLength();
            
            int j;
            for (j = 0; j <= length - 1; j++) {
                String currentAttName = atts.getLocalName(j);
                String currentAttContent = atts.getValue(j);
                
                attributes = attributes + currentAttName + "=" + currentAttContent + " ";
            }
        }
        
        sqlStatementFiles = "INSERT INTO files(id,name) VALUES(" + currentFileId + "," + sw + currentSiblingNumber + sw + ")";
        sqlStatementPaths = "INSERT INTO paths(id,path,file) VALUES(" + currentPathId + "," + sw + oldDeweyId + sw + "," + currentFileId + ")";
                
        if (!attributes.isEmpty()) {
            sqlStatement = "INSERT INTO dewey_edges(dewey,path_id,value,attributes,datatype,fahter_id) VALUES(" + sw + currentDeweyId + sw + ","
                                                         + /* currentPathId */ "1" + "," 
                                                         + sw + value + sw + ","
                                                         + /* atts.toString() */ sw + attributes + sw + ", 'tag')";
        } else {
        sqlStatement = "INSERT INTO dewey_edges(dewey,path_id,value,attributes,datatype,father_id) VALUES(" + sw + currentDeweyId + sw + ","
                                                         + currentPathId + "," 
                                                         + sw + value + sw + ","
                                                         + /* atts.toString() */ "NULL, 'tag')";
        }
        
//        try {
//            statement.execute(sqlStatementFiles);
//        } catch (SQLException ex) {
//            Logger.getLogger(XMLParser.class.getName()).log(Level.SEVERE, null, ex);
//            System.out.println(sqlStatementFiles);
//        }
//        
//        try {
//            statement.execute(sqlStatementPaths);
//        } catch (SQLException ex) {
//            Logger.getLogger(XMLParser.class.getName()).log(Level.SEVERE, null, ex);
//            System.out.println(sqlStatementPaths);
//        }       
// 
//        try {
//            statement.execute(sqlStatement);
//        } catch (SQLException ex) {
//            Logger.getLogger(XMLParser.class.getName()).log(Level.SEVERE, null, ex);
//            System.out.println(sqlStatement);
//        }       

        try {
            statement.addBatch(sqlStatementFiles);
            statement.addBatch(sqlStatementPaths);
            statement.addBatch(sqlStatement);
        } catch (SQLException ex) {
            Logger.getLogger(ShakespeareXMLParser.class.getName()).log(Level.SEVERE, null, ex);
        }

        currentLevel++;
        currentFileId++;
        currentPathId++;
    }

    @Override
    public void endElement(String uri, String name, String qName) {
        
	// if ("".equals (uri))
	//     System.out.println("End element: " + qName);
	// else
	//     System.out.println("End element:   {" + uri + "}" + name);
        
        // String t = currentDeweyId.substring((currentDeweyId.length() - 1), currentDeweyId.length());
        // currentSiblingNumber = (Integer.valueOf(t)) + 1;
        
        int i;
        for (i = (currentDeweyId.length()) - 1; (currentDeweyId.charAt(i) != '.') && (i > 0); i--) {
            continue;
        }
        currentDeweyId = currentDeweyId.substring(0, i);
        
        currentText = "";
        currentLevel--;        
    }
        
    public void addFile(String path) {
        
        FileReader file = null;
        
        if(path == null)
            return;
        
        try {
            file = new FileReader(path);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(XMLParser.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        if(file != null)
            files.add(file);
        else
            System.out.println("Error creating FileReader of XML file !");
    }
    
    
    public void run() {

        try {
            xr = XMLReaderFactory.createXMLReader();        
        } catch (SAXException ex) {
            Logger.getLogger(XMLParser.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        xr.setContentHandler(this);
	xr.setErrorHandler(this);

        for(FileReader file: files) {
            
            try {
                
                xr.parse(new InputSource(file));
                
            } catch (IOException ex) {
                Logger.getLogger(XMLParser.class.getName()).log(Level.SEVERE, null, ex);
            } catch (SAXException ex) {
                Logger.getLogger(XMLParser.class.getName()).log(Level.SEVERE, null, ex);
            }
	}
        
    }
     
}
